package cn.tyoui.string;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

import cn.tyoui.set.ListTools;
import cn.tyoui.tools.Tools;

/**
 * 字符串常用工具类
 *
 * @author 张伟
 * @version 1.0
 */
public class StringTools implements Tools {
    private static StringTools tools = null;

    /**
     * 单列模式初始化
     *
     * @return 单列类
     */
    public static StringTools initTool() {
        if (tools == null)
            return tools = new StringTools();
        return tools;
    }

    private StringTools() {
    }

    /**
     * 按照切割模式切割字符串
     *
     * @param str 要切割的字符串
     * @param cut 切割字符串样式
     * @return 返回被切割字符串链表
     */
    public List<String> split(String str, String cut) {
        return ListTools.initTool().arrList(str.split(cut));
    }

    /**
     * 分割字符串为一个字符
     *
     * @param str 要分割的字符串
     * @return 单个字符链表
     */
    public List<String> split(String str) {
        int length = str.length();
        List<String> list = new ArrayList<>(length);
        for (int i = 0; i < length; i++)
            list.add(str.substring(i, i + 1));
        return list;
    }

    /**
     * 字符串数组转换成字符串
     *
     * @param array 字符串数组
     * @return 字符串
     */
    public String arrayString(String... array) {
        String string = "";
        for (String str : array)
            string += str;
        if (string == "")
            return null;
        return string;
    }

    /**
     * 字符串链表转换成字符串
     *
     * @param list 字符串链表
     * @return 字符串
     */
    public String listString(List<String> list) {
        String[] strings = new String[list.size()];
        for (int i = 0; i < list.size(); i++)
            strings[i] = new String(list.get(i));
        return arrayString(strings);
    }

    /**
     * 过滤一行数据
     *
     * @param str    一行数据
     * @param filter 过滤规则
     * @return 过滤之后的数据
     */
    public String filterString(String str, String[] filter) {
        if (filter == null)
            return str;
        for (String string : filter)
            if (str.contains(string))
                return null;
        return str;
    }

    /**
     * 过滤字符串链表
     *
     * @param strList    字符串链表
     * @param filter     过滤的字符串
     * @param filterFlag 是否保存过滤字符串，true提取过滤字符串一致。false保存过滤后的字符串。
     * @return 过滤(提取)以后的字符串链表。
     */
    public List<String> filterListString(List<String> strList, String filter, boolean filterFlag) {
        List<String> list = new ArrayList<>();
        for (String string : strList)
            if (string.contains(filter)) {
                if (filterFlag)
                    list.add(string);
            } else if (!filterFlag)
                list.add(string);
        return list;
    }

    /**
     * 判断一个字符串是否为 null 或 空串 或 空白
     *
     * @param source 需要判断的字符串
     * @return 当字符串为 null 或 为 空白、空串 时返回 true
     */
    public boolean empty(String source) {
        return source == null || source.trim().isEmpty();
    }

    /**
     * 判断一个字符串是否不是null且不是空串、不是空白
     *
     * @param source 需要判断的字符串
     * @return 当 字符串是不是null且不是空串也不是空白时返回 true
     */
    public boolean notEmpty(String source) {
        return source != null && source.trim().length() > 0;
    }

    /**
     * 判断一个字符串变量是否为 null
     *
     * @param source 需要判断的字符串
     * @return 当 字符串变量 为 null 时返回 true
     */
    public boolean isNull(String source) {
        return source == null;
    }

    /**
     * 判断一个字符串是否为 空串
     *
     * @param source 需要判断的字符串
     * @return 当字符串中的值是 空串 或 空白 串时返回 true
     */
    public boolean emptyString(String source) {
        return (source != null) && source.length() == source.trim().length();
    }

    /**
     * 判断一个字符串是否为 空白 串
     *
     * @param source 需要判断的字符串
     * @return 当字符串中的值是 空白 串时返回 true
     */
    public boolean blank(String source) {
        return (source != null) && source.length() > source.trim().length();
    }

    /**
     * 比较两个非空(不是null,不是空串,不是空白)字符串是否"相等"
     *
     * @param one      第一个需要比较的字符串
     * @param theOther 另一个参与比较的字符串
     * @return 当 两个字符串 都不为空串 且 内容完全一致 (剔除首尾空白后、大小写也一致)时返回 true
     */
    public boolean equals(String one, String theOther) {
        return equals(one, theOther, true, false);
    }

    /**
     * 比较两个字符串是否 "相等"
     *
     * @param one         参与比较的第一个字符串
     * @param theOther    参与比较的另一个字符串
     * @param escapeSpace 是否需要剔除首尾空白 ( true 表示需要剔除首尾空白，false 表示不剔除 )
     * @param ignoreCase  是否忽略大小写 ( true 表示忽略大小写 ，false 表示不忽略大小写 )
     * @return 是否相等
     */
    public boolean equals(String one, String theOther, boolean escapeSpace, boolean ignoreCase) {
        if (one == null || theOther == null)
            return false;
        if (escapeSpace) {
            one = one.trim();
            theOther = theOther.trim();
        }
        return ignoreCase ? one.equalsIgnoreCase(theOther) : one.equals(theOther);
    }

    /**
     * 随机生成一个 32 位长度的 字符串( UUID )
     *
     * @return 32位的字符串
     */
    public String random() {
        UUID uuid = UUID.randomUUID();
        String uuidString = uuid.toString();
        uuidString = uuidString.replace("-", "");
        uuidString = uuidString.toUpperCase();
        return uuidString;
    }

    /**
     * 通过 SHA1 对字符串进行加密
     *
     * @param source 需要加密的字符串
     * @return 加密后的字符串
     */
    public String sha1(String source) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            return messageToString(md);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    /**
     * 将MessageDigest对象转换成字符串
     *
     * @param md MessageDigest对象
     * @return 字符串
     * @throws NoSuchAlgorithmException 转换异常
     */
    public String messageToString(MessageDigest md) throws NoSuchAlgorithmException {
        BigInteger bigInteger = new BigInteger(md.digest());
        String md5Code = bigInteger.toString();
        if (md5Code.length() == 31)
            return "0" + md5Code;
        return md5Code;
    }

    /**
     * 对 给定字符串 进行 md5 加密
     *
     * @param source 待加密的字符串
     * @return 加密后的字符串
     */
    public String md5(String source) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            return messageToString(md);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    /**
     * 根据Unicode编码完美的判断中文汉字和符号
     *
     * @param c 中文字符
     * @return 是否是中文汉字
     */
    public boolean IsChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否包含中文汉字
     *
     * @param strName 中文字符串
     * @return 是否包含中文
     */
    public boolean isChineseHave(String strName) {
        char[] ch = strName.toCharArray();
        for (int i = 0; i < ch.length; i++)
            if (IsChinese((char) ch[i]))
                return true;
        return false;
    }

    /**
     * 判断是否只有中文汉字
     *
     * @param strName 中文字符串
     * @return 是否全是中文
     */
    public boolean isChineseAll(String strName) {
        char[] ch = strName.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            if (!IsChinese((char) ch[i]))
                return false;
        }
        return true;
    }


    /**
     * 对字符串进行base64加密
     *
     * @param text 字符串
     * @return 加密后的字符串
     */
    public String Base64(String text) {
        return Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 对base64进行解密
     *
     * @param base64 加密的base64
     * @return 解密后的字符串
     */
    public String decodeBase64(String base64) {
        return new String(Base64.getDecoder().decode(base64), StandardCharsets.UTF_8);
    }

}
